﻿using System;
using System.Web.Mvc;
using FlitBit.Core;

namespace FlitBit.Dto.Mvc
{
	public class DtoModelBinderProvider : IModelBinderProvider
	{
		/// <summary>
		/// Returns the model binder for the specified type.
		/// </summary>
		/// <returns>
		/// The model binder for the specified type.
		/// </returns>
		/// <param name="modelType">The type of the model.</param>
		public IModelBinder GetBinder(Type modelType)
		{
			if (modelType.IsAbstract)
			{
				var factory = FactoryProvider.Factory;
				if (factory.CanConstruct(modelType))
				{
					var finalType = factory.GetImplementationType(modelType);
					if (!finalType.IsAbstract && finalType.GetConstructor(Type.EmptyTypes) != null)
					{
						var binderType = typeof(DtoModelBinder<>).MakeGenericType(finalType);
						var meta = ModelMetadataProviders.Current.GetMetadataForType(null, finalType);
						return
							(IModelBinder)
								Activator.CreateInstance(binderType, new object[] {meta});
					}
				}
			}
			return null;
		}
	}

	class DtoModelBinder<T> : DefaultModelBinder
		where T : class, new()
	{
		readonly ModelMetadata _metadata;

		public DtoModelBinder(ModelMetadata meta)
		{
			_metadata = meta;
		}

		public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
		{
			if (bindingContext.ModelType.IsAssignableFrom(typeof(T)))
			{
				bindingContext.ModelMetadata = _metadata;
				return base.BindModel(controllerContext, bindingContext);
			}
			return null;
		}
	}
}
